/*
 * Printers.c
 *
 *  Created on: 24/apr/2013
 *      Authors: Ialenti Andrea, Marangon Fabio
 */

#include "../headers/CPLEXProblemGenerator.h"
#include "../headers/CPLEXProblemSolver.h"
#include "../headers/Printer.h"
#include "../headers/StatusCodes.h"
#include "../headers/Utility.h"

#include <math.h>
#include <stdio.h>
#include <string.h>

Status printNodes(const Graph *g, _IO_FILE *ch) {
	int i;

	fprintf(ch, "\n\nGraph nodes: \n");
	for (i = 0; i < g->size; i++)
		fprintf(ch, "Node v%d coordinates: (%0.4f, %0.4f).\n", i, g->nodes[i].x, g->nodes[i].y);
	return SUCCESS;
}

Status printCosts(const Graph *g, _IO_FILE *ch) {
	int i, j;

	fprintf(ch, "\n\nGraph edges costs: \n");
	fprintf(ch, "i\\j | ");

	for (i = 0; i < g->size; i++)
		fprintf(ch, "  %d    ", i);
	fprintf(ch, " |\n");

	for (i = 0; i < g->size; i++) {
		fprintf(ch, "%d   | ", i);

		for (j = 0; j < g->size; j++)
			if (j < i)
				fprintf(ch, "  -    ");
			else
				fprintf(ch, "%0.4f ", g->edges[i][j].cost);

		fprintf(ch, " |\n");
	}
	return SUCCESS;
}

Status printCostsTree(const OneTree *t, _IO_FILE *ch) {
	int i, j;

	fprintf(ch, "\n\n1-tree edges costs: \n");
	fprintf(ch, "i\\j | ");

	for (i = 0; i < t->size; i++)
		fprintf(ch, "  %d    ", i);
	fprintf(ch, " |\n");

	for (i = 0; i < t->size; i++) {
		fprintf(ch, "%d   | ", i);

		for (j = 0; j < t->size; j++)
			if (j < i)
				fprintf(ch, "  -    ");
			else
				fprintf(ch, "%0.4f ", t->costs[i][j]);

		fprintf(ch, " |\n");
	}
	return SUCCESS;
}

Status printIntMatrix(int **mat, int rows, int cols, _IO_FILE *ch) {
	int i, j;
	fprintf(ch, "\n");
	for (i = 0; i < rows; i++) {
		for (j = 0; j < cols; j++)
			fprintf(ch, "%d ", mat[i][j]);
		fprintf(ch, "\n");
	}
	return SUCCESS;
}

Status printDblMatrix(double **mat, int rows, int cols, _IO_FILE *ch) {
	int i, j;
	fprintf(ch, "\n");
	for (i = 0; i < rows; i++) {
		for (j = 0; j < cols; j++)
			fprintf(ch, "%0.2f ", mat[i][j]);
		fprintf(ch, "\n");
	}
	return SUCCESS;
}

Status plotGraph(const Config *cfg, const Graph *g, const char *fName) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotGraph");

	int i, j;

	//	Set window title.
	char *title = initCharArray(cfg->NAME_LEN);
	double origEdges = g->size * (g->size - 1) / 2;
	sprintf(title, "Pruned graph for '%s': %d edges survived (%0.1f%%)", g->name, g->edgeCnt, 100 * g->edgeCnt / (double)origEdges);

	//	Configure the plotter.
	gnuplot_setstyle(cfg->plt, "linespoints");
	gnuplot_set_xlabel(cfg->plt, "X-axis");
	gnuplot_set_ylabel(cfg->plt, "Y-axis");
	gnuplot_cmd(cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_H, cfg->SIZE_H);
	gnuplot_cmd(cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(cfg->plt, "set grid");
	gnuplot_cmd(cfg->plt, "set style line 1 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", cfg->COLOR_GREEN);

	//	Create the file with the graph points to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		freeCharArray(title);
		return ERR_WRITE_FILE;
	}

	//	Store the coordinates of all the edges.
	for (i = 0; i < g->size - 1; i++) {
		for (j = i + 1; j < g->size; j++) {
			if (!(g->edges[i][j].cost > -cfg->EPS && g->edges[i][j].cost < cfg->EPS) && g->edges[i][j].cost < cfg->INF) {
				fprintf(file, "%.18e %.18e\n", g->edges[i][j].start->x, g->edges[i][j].start->y);
				fprintf(file, "%.18e %.18e\n", g->edges[i][j].end->x, g->edges[i][j].end->y);
			}
		}
		fprintf(file, "\n");
	}
	fclose(file);

	//	Plot the graph.
	gnuplot_cmd(cfg->plt, "plot \"%s\" with %s ls 1 title \"Graph\"", fName, cfg->plt->pstyle);

	freeCharArray(funcName);
	freeCharArray(title);
	return SUCCESS;
}

Status plotCPLEXSol(const Config *cfg, const double *x, const Problem *p, const Graph *g, const char *fName, const char *title, const char *color) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotCPLEXSol");

	int i, idx1, idx2;

	//	Save only the edges chosen in the CPLEX solution.
	Line *lines = initLineArray(p->edges);
	int cnt = 0;
	for (i = 0; i < p->edges; i++)
		if (x[i] > 1 - cfg->EPS) {
			getEdgeNodes(p, i, &idx1, &idx2);

			//	Copy the coordinates.
			lines[cnt].sX = g->edges[idx1][idx2].start->x;
			lines[cnt].sY = g->edges[idx1][idx2].start->y;
			lines[cnt].eX = g->edges[idx1][idx2].end->x;
			lines[cnt].eY = g->edges[idx1][idx2].end->y;
			cnt++;
		}

	//	Configure the plotter.
	gnuplot_setstyle(cfg->plt, "linespoints");
	gnuplot_set_xlabel(cfg->plt, "X-axis");
	gnuplot_set_ylabel(cfg->plt, "Y-axis");
	gnuplot_cmd(cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_H, cfg->SIZE_H);
	gnuplot_cmd(cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(cfg->plt, "set grid");
	gnuplot_cmd(cfg->plt, "set style line 1 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", color);

	//	Create the file with the edges coordinates to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		freeLineArray(lines);
		return ERR_WRITE_FILE;
	}

	//	Store the coordinates of all the edges separately.
	for (i = 0; i < cnt; i++) {
		fprintf(file, "%.18e %.18e\n", lines[i].sX, lines[i].sY);
		fprintf(file, "%.18e %.18e\n\n", lines[i].eX, lines[i].eY);
	}
	fclose(file);

	//	Plot the graph.
	gnuplot_cmd(cfg->plt, "plot \"%s\" with %s ls 1 title \"Graph\"", fName, cfg->plt->pstyle);

	freeCharArray(funcName);
	freeLineArray(lines);
	return SUCCESS;
}

Status plotCPLEXSubTours(const Config *cfg, const cbData *myData, const int *cLengths, int nCycles, const int *cycles, const char *fName, const char *title) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotCPLEXSubTours");

	int i, j, offset, cnt = 0;
	Line *lines = initLineArray(myData->p->nodes + nCycles);
	for (i = 0, offset = 0; i < nCycles; i++, offset += cLengths[i - 1]) {

		for (j = offset; j < offset + cLengths[i] - 1; j++) {

			//	Copy the coordinates.
			lines[cnt].sX = myData->g->nodes[cycles[j]].x;
			lines[cnt].sY = myData->g->nodes[cycles[j]].y;
			lines[cnt].eX = myData->g->nodes[cycles[j + 1]].x;
			lines[cnt].eY = myData->g->nodes[cycles[j + 1]].y;
			cnt++;
		}

		//	Close the cycle.
		lines[cnt].sX = myData->g->nodes[cycles[offset + cLengths[i] - 1]].x;
		lines[cnt].sY = myData->g->nodes[cycles[offset + cLengths[i] - 1]].y;
		lines[cnt].eX = myData->g->nodes[cycles[offset]].x;
		lines[cnt].eY = myData->g->nodes[cycles[offset]].y;
		cnt++;
	}

	//	Configure the plotter.
	gnuplot_setstyle(myData->cfg->plt, "linespoints");
	gnuplot_set_xlabel(myData->cfg->plt, "X-axis");
	gnuplot_set_ylabel(myData->cfg->plt, "Y-axis");
	gnuplot_cmd(myData->cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(myData->cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_H, cfg->SIZE_H);
	gnuplot_cmd(myData->cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(myData->cfg->plt, "set grid");
	gnuplot_cmd(myData->cfg->plt, "set style line 1 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", cfg->COLOR_BLUE);

	//	Create the file with the edges coordinates to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		freeLineArray(lines);
		return ERR_WRITE_FILE;
	}

	//	Store the coordinates of all the edges separately.
	for (i = 0, offset = 0, j = 0; i < cnt; i++) {
		fprintf(file, "%.18e %.18e\n", lines[i].sX, lines[i].sY);
		fprintf(file, "%.18e %.18e\n\n", lines[i].eX, lines[i].eY);
		if(i == offset + cLengths[j]) {
			offset += cLengths[j++];
			fprintf(file, "\n\n");
		}
	}
	fclose(file);

	//	Plot the graph.
	gnuplot_cmd(myData->cfg->plt, "plot \"%s\" with %s ls 1 title \"Graph\"", fName, myData->cfg->plt->pstyle);

	freeCharArray(funcName);
	freeLineArray(lines);
	return SUCCESS;
}

Status plotOneTree(const Config *cfg, const OneTree *t, const char *fName, const char *title) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotOneTree");

	int i;

	//	Configure the plotter.
	gnuplot_setstyle(cfg->plt, "linespoints");
	gnuplot_set_xlabel(cfg->plt, "X-axis");
	gnuplot_set_ylabel(cfg->plt, "Y-axis");
	gnuplot_cmd(cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_H, cfg->SIZE_H);
	gnuplot_cmd(cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(cfg->plt, "set grid");
	gnuplot_cmd(cfg->plt, "set style line 1 linetype 1 linewidth 1 pointtype 7 pointsize 1.5 linecolor rgb \"%s\"", cfg->COLOR_BLACK);
	gnuplot_cmd(cfg->plt, "set style line 2 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", cfg->COLOR_RED);

	//	Create the file with the 1-tree points to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		return ERR_WRITE_FILE;
	}

	//	Store the coordinates of all the edges of the spanning tree.
	for (i = 0; i < t->size; i++) {
		if (!(t->edges[i].cost > -cfg->EPS && t->edges[i].cost < cfg->EPS)) {
			fprintf(file, "%.18e %.18e\n", t->edges[i].start->x, t->edges[i].start->y);
			fprintf(file, "%.18e %.18e\n", t->edges[i].end->x, t->edges[i].end->y);
			fprintf(file, "%.18e %.18e\n", t->edges[i].start->x, t->edges[i].start->y);
		}
		fprintf(file, "\n");
	}


	//	Store the coordinates of the 2 edges that form the cycle in the 1-tree.
	fprintf(file, "\n\n%.18e %.18e\n", t->edges[0].end->x, t->edges[0].end->y);
	fprintf(file, "%.18e %.18e\n", t->edges[0].start->x, t->edges[0].start->y);
	fprintf(file, "%.18e %.18e\n", t->edges[1].end->x, t->edges[1].end->y);

	fclose(file);

	//	Plot the 1-tree.
	gnuplot_cmd(cfg->plt, "plot \"%s\" index 0 with %s ls 2 title \"1-Tree\", \"%s\" index 1 with %s ls 1 title \"starting node v0 or \\nmin-cost edges e0, e1\"", fName, cfg->plt->pstyle, fName, cfg->plt->pstyle);

	freeCharArray(funcName);
	return SUCCESS;
}

Status plotTour(const Config *cfg, const OneTree *t, const char *fName, const char *title, const char *color) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotTour");

	int i;

	//	Configure the plotter.
	gnuplot_setstyle(cfg->plt, "linespoints");
	gnuplot_set_xlabel(cfg->plt, "X-axis");
	gnuplot_set_ylabel(cfg->plt, "Y-axis");
	gnuplot_cmd(cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_H, cfg->SIZE_H);
	gnuplot_cmd(cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(cfg->plt, "set grid");
	gnuplot_cmd(cfg->plt, "set style line 1 linetype 1 linewidth 1 pointtype 7 pointsize 1.5 linecolor rgb \"%s\"", cfg->COLOR_BLACK);
	gnuplot_cmd(cfg->plt, "set style line 2 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", color);

	//	Create the file with the 1-tree points to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		return ERR_WRITE_FILE;
	}

	//	Store the coordinates of all the edges of the spanning tree.
	for (i = 0; i < t->size; i++) {
		if (!(t->edges[i].cost > -cfg->EPS && t->edges[i].cost < cfg->EPS)) {
			fprintf(file, "%.18e %.18e\n", t->edges[i].start->x, t->edges[i].start->y);
			fprintf(file, "%.18e %.18e\n", t->edges[i].end->x, t->edges[i].end->y);
			fprintf(file, "%.18e %.18e\n", t->edges[i].start->x, t->edges[i].start->y);
		}
		fprintf(file, "\n");
	}

	//	Store the coordinates for the starting node of the tour.
	fprintf(file, "\n\n%.18e %.18e\n", t->edges[t->v0].start->x, t->edges[t->v0].start->y);

	fclose(file);

	//	Plot the 1-tree.
	gnuplot_cmd(cfg->plt, "plot \"%s\" index 0 with %s ls 2 title \"1-Tree\", \"%s\" index 1 with %s ls 1 title \"starting node v0 or \\nmin-cost edges e0, e1\"", fName, cfg->plt->pstyle, fName, cfg->plt->pstyle);

	freeCharArray(funcName);
	return SUCCESS;
}

Status plotFunction(const Config *cfg, const funcLu *f, const char *fName) {
	char *funcName = initCharArray(cfg->NAME_LEN);
	sprintf(funcName, "plotFunction");

	int i;

	//	Set window title.
	char *title = initCharArray(cfg->NAME_LEN);
	sprintf(title, "Function L(u) for '%s'. LB = %0.2f", f->name, f->best);

	//	Configure the plotter.
	gnuplot_setstyle(cfg->plt, "lines");
	gnuplot_set_xlabel(cfg->plt, "step #");
	gnuplot_set_ylabel(cfg->plt, "L(u)");
	gnuplot_cmd(cfg->plt, "set terminal %s reset", cfg->TERM_X);
	gnuplot_cmd(cfg->plt, "set term %s size %d, %d", cfg->TERM_X, cfg->SIZE_W, cfg->SIZE_H);
	gnuplot_cmd(cfg->plt, "set terminal %s title \"%s\"", cfg->TERM_X, title);
	gnuplot_cmd(cfg->plt, "set grid");
	gnuplot_cmd(cfg->plt, "set style line 1 linetype 2 linewidth 1.2 pointtype 1 pointsize 1 linecolor rgb \"%s\"", cfg->COLOR_RED);
	gnuplot_cmd(cfg->plt, "set style line 2 linetype 1 linewidth 1 pointtype 7 pointsize 0.9 linecolor rgb \"%s\"", cfg->COLOR_GREEN);

	//	Create the file with the 1-tree points to be plotted.
	FILE *file;
	if ((file = fopen(fName, "w")) == NULL) {
		fprintf(stdout, "***'%s': cannot create temporary file: exiting plot!\n", funcName);
		freeCharArray(funcName);
		freeCharArray(title);
		return ERR_WRITE_FILE;
	}

	//	Store the function values in a file.
	for (i = 0; i < f->size; i++)
		fprintf(file, "%.18e\n", f->L[i]);
	fclose(file);

	//	Plot the function L(u).
	int Ymin = round(f->best * 0.35);
	int Ymax = round(f->upperBound) + 10;
	gnuplot_cmd(cfg->plt, "plot [0:%d] [%d:%d] \"%s\" with %s ls 2 title \"Function L(u)\"", f->size, Ymin, Ymax, fName, cfg->plt->pstyle);
	gnuplot_cmd(cfg->plt, "f(x)=%0.2f", f->upperBound);
	gnuplot_cmd(cfg->plt, "replot f(x) with %s ls 1 title \"Upper bound used\"", cfg->plt->pstyle);

	freeCharArray(funcName);
	freeCharArray(title);
	return SUCCESS;
}
